<template>
  <div class="demo">
    <div
      ref="d3demo2Ref"
      :style="{
        width: width + 'px',
        height: height + 'px'
      }"
    ></div>
  </div>
</template>

<script setup lang="ts">
import { onDeactivated, onMounted, onUnmounted, ref } from 'vue'
import * as d3 from 'd3'
import { demoData1 } from './data'
import { CommonUtil } from 'hippo-module-core/utils'

interface UserType {
  name: string
  age: number
}

const d3demo2Ref = ref()
const tooltip = ref<any>(null)
const tooltipId = 'd3-tooltip' + CommonUtil.UUID16()

const width = 690
const height = 500
const margin = { top: 30, bottom: 120, left: 120, right: 60 }

const colorScale = d3.scaleOrdinal().domain(d3.range(demoData1.length)).range(d3.schemeCategory10)

const init = () => {
  d3.select(d3demo2Ref.value).append('svg').attr('height', height).attr('width', width)
  const svg = d3.select(d3demo2Ref.value).select('svg')
  const inner = svg
    .append('g')
    .attr('id', 'innerContainer')
    .attr('height', height - margin.top - margin.bottom)
    .attr('width', width - margin.left - margin.right)
    .attr('transform', `translate(${margin.left},${margin.top})`)

  //比例尺
  const yScale = d3
    .scaleLinear()
    .domain([0, d3.max(demoData1, (d: UserType) => d.age)])
    .range([inner.attr('height'), 0])

  const xScale = d3
    .scaleBand()
    .domain(demoData1.map((item) => item.name))
    .range([0, inner.attr('width')])
    .padding(0.15)

  //x轴和Y轴
  const xAxis = d3.axisBottom(xScale)
  const yAxis = d3.axisLeft(yScale)

  //x轴
  inner
    .append('g')
    .call(xAxis)
    .attr('id', 'xAxis')
    .attr('transform', `translate(0,${inner.attr('height')})`)
    .attr('font-size', '13px')
    .attr('color', '#aaa')

  //Y轴
  inner.append('g').call(yAxis).attr('id', 'yAxis').attr('font-size', '13px').attr('color', '#aaa')

  // 修改x和y轴的label样式
  inner.selectAll('.tick').select('text').attr('color', '#222')

  inner
    .select('#xAxis')
    .selectAll('.tick')
    .select('text')
    .style('writing-mode', 'tb-rl')
    .attr('textLength', 100)
    .attr('y', '55px')

  const lineGenerator = d3
    .line()
    .x((d: UserType, i: number) => {
      return xScale(d.name) + 15
    })
    .y((d: UserType, i: number) => {
      return yScale(d.age) + 2
    })
    .curve(d3.curveBasis)

  inner
    .append('g')
    .attr('id', 'lineContainer')
    .append('path')
    .attr('d', () => {
      return lineGenerator(demoData1)
    })
    .attr('fill', 'none')
    .attr('stroke', 'orangered')
    .attr('stroke-width', 2)

  // 柱状图文本信息
  inner
    .append('g')
    .attr('id', 'labelContainer')
    .selectAll('label')
    .data(demoData1)
    .join('text')
    .attr('fill', (d: UserType, i: number) => colorScale(i))
    .attr('font-size', '0.85em')
    .attr('y', (d: UserType) => yScale(d.age))
    .attr('x', (d: UserType, i: number) => xScale(d.name) + xScale.bandwidth() / 2 - 10)
    .text((d: UserType, i: number) => d.age + '岁')
    .attr('cursor', 'pointer')
    .on('mouseover', (d: any, data: UserType) => {
      const ele = d3.select(d.srcElement)
      ele.transition().duration(300).attr('opacity', '0.65')
      tooltipVisible(d, data)
    })
    .on('mouseout', (d: any, data: UserType) => {
      const ele = d3.select(d.srcElement)
      ele.transition().duration(300).attr('opacity', '1')

      tooltipHidden()
    })

  //标题
  inner
    .append('text')
    .attr('x', `${inner.attr('width') / 2}`)
    .attr('y', -15)
    .attr('text-anchor', 'middle')
    .attr('font-size', '15px')
    .attr('font-weight', '550')
    .text('年龄统计')
}

const tooltipHidden = () => {
  tooltip.value.transition().duration(300).style('opacity', 0).style('display', 'none')
}

const tooltipVisible = (event: any, data: UserType) => {
  tooltip.value.transition().duration(300).style('opacity', 1).style('display', 'block')
  tooltip.value
    .html(
      `<div>
         ${data.name} : ${data.age} 岁
      </div>`
    )
    .style('left', event.pageX + 2 + 'px')
    .style('top', event.pageY + 2 + 'px')
}

const createTooltip = () => {
  tooltip.value = d3
    .select('body')
    .append('div')
    .attr('id', tooltipId)
    .style('opacity', 0)
    .style('position', 'fixed')
    .style('font-size', '12px')
    .style('text-align', 'center')
    .style('background-color', 'rgba(255,255,255,0.95)')
    .style('border-radius', '3px')
    .style('box-shadow', '0px 0px 5px rgba(10, 10, 10,0.2)')
    .style('padding', '8px')
    .style('z-index', '998')
    .style('cursor', 'pointer')
    .style('display', 'none')
}

const removeTooltip = () => {
  const tooltip = d3.select('body').select('#' + tooltipId)
  if (tooltip) {
    tooltip.remove()
  }
}

onDeactivated(() => {
  removeTooltip()
})

onMounted(() => {
  init()
  createTooltip()
})
</script>

<style lang="scss" scoped>
.demo {
  width: 100%;
  height: 100%;
  display: flex;
}
</style>
